package org.dreamwork.jasmine2.i18n;

import org.dreamwork.i18n.IResourceAdapter;
import org.dreamwork.i18n.IResourceManager;
import org.dreamwork.i18n.LocaleUtil;
import org.dreamwork.jasmine2.configure.JasmineConfig;
import org.dreamwork.jasmine2.engine.HttpContext;
import org.dreamwork.jasmine2.web.IWebControl;
import org.dreamwork.jasmine2.web.controls.Page;
import org.dreamwork.jasmine2.web.controls.UserControl;
import org.dreamwork.peony.DataBinder;
import org.dreamwork.util.FileInfo;
import org.dreamwork.util.StringUtil;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by IntelliJ IDEA.
 * User: seth.yang
 * Date: 12-10-18
 * Time: 下午6:31
 */
public class I18nUtil {
    private static final Pattern PATTERN = Pattern.compile ("\\$\\{\\s*(.*?)\\s*\\}");
    private static final Pattern STRING_PATTERN = Pattern.compile ("^\\\".*\\\"$");
    private static final Pattern NUMBER_PATTERN = Pattern.compile ("^-?[\\d]+(\\.[\\d]+)?$");
    private static final Pattern CONTEXT_PATTERN = Pattern.compile ("^\\((.*?)\\)(\\.(.*?))*$");

    public static String eval (String text, IWebControl control) {
        if (text.contains ("${")) {
            Matcher m = PATTERN.matcher (text);
            StringBuffer buff = new StringBuffer ();
            Page page = control.getPage ();
            if (StringUtil.isEmpty (page.getResource ()) && page instanceof UserControl) {
                IWebControl p = page.getParent ();
                if (p != null)
                    page = p.getPage ();
            }
            HttpContext context = HttpContext.current ();
            ServletContext application = context.getApplication ();
            IResourceManager manager = (IResourceManager) application.getAttribute (JasmineConfig.JASMINE_I18N_HOLDER);
            IResourceAdapter adapter = manager.getResourceAdapter (page.getResource ());
            Locale locale = findCurrentLocale (context);

            while (m.find ()) {
                String key = m.group (1);
                String replacement;
                if (key.indexOf (',') > 0) {
                    String[] a = key.split (",");
                    key = a [0].trim ();
                    Object[] parameters = build (a, control);
                    replacement = adapter.getString (locale, key, parameters);
                } else {
                    replacement = adapter.getString (locale, key);
                }

                m.appendReplacement (buff, replacement);
            }
            m.appendTail (buff);
            text = buff.toString ();
        }
        return text;
    }

    public static Object[] build (String[] expressions, IWebControl control) {
        Object[] parameters = new Object[expressions.length - 1];
        Page page = control.getPage ();
        HttpContext context = page.getHttpContext ();
        for (int i = 1; i < expressions.length; i ++) {
            String name = expressions [i].trim ();

            if (isText (name)) {
                parameters [i - 1] = name.substring (1, name.length () - 1);
                continue;
            }
            if (isNumber (name)) {
                parameters [i - 1] = name;
                continue;
            }

            Matcher m = CONTEXT_PATTERN.matcher (name);
            if (m.matches ()) {
                Object value = evalContextAttribute (m, name, context);
                if (value != null) {
                    parameters [i - 1] = value;
                    continue;
                }
            }

            Object o = context.findAttribute (name);
            if (o != null) {
                parameters [i - 1] = o;
                continue;
            }

            o = DataBinder.eval (page, name);
            if (o != null) {
                parameters [i - 1] = o;
                continue;
            }

            o = control.getAttribute (name);
            if (o != null) {
                parameters [i - 1] = o;
                continue;
            }
            o = page.getAttribute (name);
            if (o != null) {
                parameters [i - 1] = o;
                continue;
            }
            try {
                o = org.dreamwork.peony.DataBinder.eval (page, name);
                if (o != null && !StringUtil.isEmpty (o.toString ())) {
                    parameters [i - 1] = o;
                    continue;
                }
            } catch (Exception ex) {
//                parameters [i - 1] = "";
            }
            parameters [i - 1] = name;
        }
        return parameters;
    }

    public static void replaceAttribute (String attrName, IWebControl control) {
        Page page = control.getPage ();
        if (StringUtil.isEmpty (page.getResource ()) && page instanceof UserControl) {
            IWebControl p = page.getParent ();
            if (p != null)
                page = p.getPage ();
        }
        HttpContext context = page.getHttpContext ();
        ServletContext application = context.getApplication ();
        HttpServletRequest request = context.getRequest ();
        Locale locale = findCurrentLocale (context);
        Map<Locale, String> map = new HashMap<Locale, String> ();

        String servletPath = request.getServletPath ();
        String contextPath = request.getContextPath ();
        String src = control.getAttribute (attrName);
        if ("".equals (contextPath.trim ())) contextPath += '/';

        String baseName = FileInfo.getFileNameWithoutExtension (src);
        String ext = FileInfo.getExtension (src);
        Pattern p = Pattern.compile ("^" + baseName + "\\.(.*?)\\." + ext + '$');
        String folder;


        if (src.startsWith (contextPath)) {
            src = src.substring (contextPath.length ());
            folder = FileInfo.getFolder (src);
        } else {
            String base = FileInfo.getFolder (servletPath);
            folder = FileInfo.getFolder (FileInfo.getAbsolutePath (base, src));
        }
        if (folder.charAt (0) != '/') folder = '/' + folder;
        Set set = application.getResourcePaths (folder);

        if (set != null) for (Object o : set) {
            String name = o.toString ();
            String fileName = FileInfo.getFileNameWithoutPath (name);
            Matcher m = p.matcher (fileName);
            if (!m.matches ()) continue;
            String language = m.group (1);
            Locale loc = LocaleUtil.parseLocale (language);
            map.put (loc, name);
        }

        Locale loc = LocaleUtil.findClosetLocale (map.keySet (), locale);
        if (loc != null) {
            if ("/".equals (contextPath)) {
                contextPath = "";
            } else if (contextPath.endsWith ("/"))
                contextPath = contextPath.substring (0, contextPath.length () - 1);
            control.setAttribute (attrName, contextPath + map.get (loc));
        }
    }

    public static String escapeI18n (String expression) {
        return expression.replace ("\\$", "$").replace ("\\{", "{").replace ("\\}", "}");
    }

    private static Object evalContextAttribute (Matcher m, String expression, HttpContext context) {
        String attrName = m.group (1);
        if (attrName == null) return null;

        Object container = context.findAttribute (attrName);
        if (container == null) return null;

        int pos = expression.indexOf (").");
        if (pos == -1) return container;

        return DataBinder.eval (container, expression);
    }

    public static boolean isText (String expression) {
        Matcher m = STRING_PATTERN.matcher (expression);
        return m.matches ();
    }

    public static boolean isNumber (String expression) {
        return NUMBER_PATTERN.matcher (expression).matches ();
    }

    private static Locale findCurrentLocale (HttpContext context) {
        HttpSession session = context.getSession ();
        Locale locale = (Locale) session.getAttribute (IWebControl.LOCALE_KEY);
        if (locale == null) {
            ServletContext application = context.getApplication ();
            locale = (Locale) application.getAttribute (JasmineConfig.DEFAULT_LOCALE);
        }
        return locale;
    }

    public static void main (String[] args) throws Exception {
        String[] s = {"javax.servlet.context.tempdir", "(javax.servlet.context.tempdir)", "(jasmine.i18n.default.locale).displayName"};
        for (String text : s) {
            Matcher m = CONTEXT_PATTERN.matcher (text);
            if (m.matches ()) {
                for (int i = 1; i < m.groupCount (); i ++) {
                    System.out.printf ("group [%d] = %s%n", i, m.group (i));
                }
                System.out.printf ("%s is context varible%n%n", text);
            } else
                System.out.printf ("%s isn't context varible%n%n", text);
        }
    }
}